#include "File.h"
#include "Exception.h"

using namespace Woo;
using namespace Woo::IO;

void File::Delete(string path)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	if(unlink(path.c_str()) == -1)
	{
		if(errno == ENOENT)
			throw FileNotFoundException(strerror(errno), __FILE__, __LINE__);
		else
			throw IOException(strerror(errno), __FILE__, __LINE__);
	}
}

void File::Copy(string sourcePath, string destPath)
{
	if(sourcePath.empty())
		throw ArgumentException("source path is empty.", __FILE__, __LINE__);

	if(destPath.empty())
		throw ArgumentException("destination path is empty.", __FILE__, __LINE__);

	FileStream sourceStream(sourcePath);
	FileStream destStream(destPath);
	sourceStream.Copy(&destStream);
	sourceStream.Close();
	destStream.Close();
}

FileStream File::Create(string path)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	return FileStream(path, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
}

FileStream File::Create(string path, int flags)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	return FileStream(path, flags, S_IRWXU|S_IRWXG|S_IRWXO);
}

FileStream File::Create(string path, int flags, mode_t mode)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	return FileStream(path, flags, mode);
}

FileStream File::Open(string path)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	return FileStream(path, O_CREAT|O_EXCL|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
}

FileStream File::Open(string path, int flags)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	return FileStream(path, flags, S_IRWXU|S_IRWXG|S_IRWXO);
}

FileStream File::Open(string path, int flags, mode_t mode)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	return FileStream(path, flags, mode);
}

void File::ReadAllByte(string path, vector<Byte>* pbuffer)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	if(pbuffer == 0)
		throw ArgumentException("pbuffer is null.", __FILE__, __LINE__);

	FileStream stream(path);
	Byte buffer[4096];
	memset(buffer, 0, 4096);
	UInt32 size = stream.GetLength();
	UInt32 readsize = 0;
	while(readsize < size)
	{
		UInt32 readcount = stream.Read(buffer, 4096);
		pbuffer->insert(pbuffer->end(), readcount, 0);
		memcpy(&pbuffer->at(readsize), buffer, readcount);
		readsize += readcount;
	}
	stream.Close();
}

void File::ReadAllByte(string path, Stream* stream)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	if(stream == 0)
		throw ArgumentException("stream is null.", __FILE__, __LINE__);

	FileStream sourceStream(path);
	sourceStream.Copy(stream);
	sourceStream.Close();
}

void File::WriteAllByte(string path, Byte* buffer, UInt32 bufferSize)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	if(buffer == 0)
		throw ArgumentException("buffer is null.", __FILE__, __LINE__);

	FileStream destStream(path);
	destStream.Write(buffer, bufferSize);
	destStream.Close();
}

void File::WriteAllByte(string path, Stream* stream)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	if(stream == 0)
		throw ArgumentException("stream is null.", __FILE__, __LINE__);

	FileStream destStream(path);
	stream->Copy(&destStream);
	destStream.Close();
}

void File::ReadAllText(string path, string* content)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	if(content == 0)
		throw ArgumentException("content is null.", __FILE__, __LINE__);

	vector<Byte> bytes;
	File::ReadAllByte(path, &bytes);
	*content = string((char*)&bytes.at(0), bytes.size());
}

string File::ReadAllText(string path)
{
	string content;
	File::ReadAllText(path, &content);
	return content;
}

void File::WriteAllText(string path, string* content)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	if(content == 0)
		throw ArgumentException("content is null.", __FILE__, __LINE__);

	File::WriteAllByte(path, (Byte*)content->c_str(), content->length());
}

bool File::Exists(string path)
{
	if(path.empty())
		throw ArgumentException("path is empty.", __FILE__, __LINE__);

	struct stat info;
	if(stat(path.c_str(), (struct stat*)&info) == -1)
		return false;
	else
		return true;
}

void File::Move(string sourceName, string destName)
{
	if(sourceName.empty())
		throw ArgumentException("source path is empty.", __FILE__, __LINE__);

	if(destName.empty())
		throw ArgumentException("destination path is empty.", __FILE__, __LINE__);

	if(rename(sourceName.c_str(), destName.c_str()) == -1)
	{
		if(errno == ENOENT)
			throw FileNotFoundException(strerror(errno), __FILE__, __LINE__);
		else
			throw IOException(strerror(errno), __FILE__, __LINE__);
	}
}

void File::CreateSymLink(string sourceName, string destName)
{
	if(sourceName.empty())
		throw ArgumentException("source path is empty.", __FILE__, __LINE__);

	if(destName.empty())
		throw ArgumentException("destination path is empty.", __FILE__, __LINE__);

	if(symlink(sourceName.c_str(), destName.c_str()) == -1)
	{
		throw IOException(strerror(errno), __FILE__, __LINE__);
	}
}

